<?php

/**
 * Ignus Framework
 *
 * @author Sergey Palyanov <sergey.palyanov@gmail.com>
 * @link http://code.google.com/p/ignus-php/
 * @license http://apache.org/licenses/LICENSE-2.0
 * @package Db
 * @subpackage Mongodb
 * @since 0.3
 */

namespace Ignus\Db\Mongodb;

use Ignus\Db\Query;

/**
 * @package Db
 * @subpackage Mongodb
 * @since 0.3
 */
class MongoQuery implements Query
{
    /**
     * @var object MongoCollection object
     */
    private $collection;

    /**
     * @var array|null Fields list to fetch
     */
    private $query;

    /**
     * @var integer Number of documents to fetch
     */
    private $limit = 0;

    /**
     * @var integer Number of documents to skip
     */
    private $offset = 0;

    /**
     * @var array Field names to fetch
     */
    private $fields = array();

    /**
     * @var array Sort fields
     */
    private $sort = null;

    /**
     * @param \MongoCollection $collection Collection
     * @param array $query Array of fields to fetch
     */
    public function __construct($collection, array $query = array())
    {
        $this->collection = $collection;
        $this->query = $query;
    }

    /**
     * Specify sorting fields
     * @param array $sort
     * @return MongoQuery
     */
    public function sort(array $sort)
    {
        $this->sort = $sort;
        return $this;
    }

    /**
     * @param integer $limit Number of documents to fetch
     * @param integer $offset Number of documents to skip
     * @return MongoQuery
     */
    public function limit($limit, $offset = 0)
    {
        $this->limit = $limit;
        $this->offset = $offset;
        return $this;
    }

    /**
     * @param array $names Field names to fetch
     * @return MongoQuery
     */
    public function fields(array $names)
    {
        $this->fields = array_fill_keys($names, 1);
        return $this;
    }

    /**
     * @return MongoCursor
     */
    private function makeQuery()
    {
        $cursor = $this->collection->find($this->query, $this->fields);

        if ($this->sort != null)
            $cursor->sort($this->sort);

        if ($this->limit > 0)
            $cursor->limit($this->limit);
        if ($this->offset > 0)
            $cursor->skip($this->offset);

        return $cursor;
    }

    /**
     * Transforms cursor data to indexed array
     * @return array Array of documents
     */
    public function getArray()
    {
        $result = array();

        foreach ($this->makeQuery() as $doc) {
            if (is_object($doc['_id']))
                $doc['_id'] = $doc['_id']->__toString();
            $result[] = $doc;
        }

        return $result;
    }

    /**
     * Fetch the first matching document
     * @return array|null
     */
    public function getOne()
    {
        return $this->collection->findOne($this->query, $this->fields);
    }

    /**
     * Fetch the first matching document
     * @param string $field Field to fetch
     * @return array|null
     */
    public function getOneField($field)
    {
        $document = $this->collection->findOne($this->query, $this->fields);
        if ($document == null)
            return null;

        return isset($document[$field]) ? $document[$field] : null;
    }

    /**
     * Returns number of documents matching criteria
     * @return integer
     * @since 0.5.4
     */
    public function count()
    {
        return $this->collection->count($this->query);
    }
}
